package eu.webhib.frmwrk.utils;

import java.security.MessageDigest;
import java.util.*;
import org.apache.commons.codec.*;
import org.apache.commons.codec.binary.*;

import org.apache.log4j.Logger;

//
public class MiscUtils {

   private static final Logger log = Logger.getLogger(MiscUtils.class);
   //
   private static Random random;
   private static MessageDigest digest;

   static {
      random = new Random(System.nanoTime() + Runtime.getRuntime().freeMemory());
   }

   private MiscUtils() {
   }

   public static void getRandom(byte[] bytes) {
      random.nextBytes(bytes);
   }

   public static byte[] getRandom(short length) {
      byte[] bytes = new byte[length];
      random.nextBytes(bytes);
      return bytes;
   }

   public static byte[] getSalt(String environmentRandom, short saltLen) {
      byte[] binary = StringUtils.getBytesUsAscii(environmentRandom);
      byte[] salt = getRandom(saltLen);

      log.trace("binary hex:   " + MiscUtils.encodeHex(binary));
      log.trace("random hex:   " + MiscUtils.encodeHex(salt));

      for (int i = 0; i < binary.length; i++) {
         salt[i % saltLen] += binary[i];
      }
      log.trace("salt hex:     " + MiscUtils.encodeHex(salt));
      return salt;
   }

   public static String encodeHex(byte[] input) {
      return Hex.encodeHexString(input);
   }

   public static byte[] decodeHex(String input) {
      try {
         return Hex.decodeHex(input.toCharArray());
      } catch (DecoderException ex) {
         log.fatal("decodeHex", ex);
         throw new IllegalArgumentException(ex);
      }
   }

   public static byte[] getDigest(String str, byte[] hex) {
      byte[] input = MiscUtils.arrayConcat(str.getBytes(), hex);
      return getDigest(input);
   }

   public static byte[] getDigest(String input) {
      log.debug("getDigest: " + input);
      return getDigest(input.getBytes());
   }

   public static byte[] getDigest(byte[] input) {
      try {
         digest = MessageDigest.getInstance("SHA-256");
         assert (digest != null);
         return digest.digest(input);
      } catch (Throwable ex) {
         log.fatal("MessageDigest for SHA", ex);
         return null;
      }
   }

   public static String encodeBase64UrlSafe(byte[] input) {
      // not chunked, but UrlSafe
      // The url-safe variation emits - and _ instead of + and / characters
      return Base64.encodeBase64URLSafeString(input);
   }

   public static byte[] decodeBase64(String input) {
      return Base64.decodeBase64(input);
   }

   public static byte[] arrayConcat(byte[] first, byte[] second) {
      byte[] result = Arrays.copyOf(first, first.length + second.length);
      System.arraycopy(second, 0, result, first.length, second.length);
      return result;
   }

   public static <T> T[] arrayConcat(T[] first, T[] second) {
      T[] result = Arrays.copyOf(first, first.length + second.length);
      System.arraycopy(second, 0, result, first.length, second.length);
      return result;
   }
}
